#include "thread_api.h"
struct t_thread_runner{
    thread_func_call func;
    void* param;
    valatile int running;
    thread_id_t thread_id;
    HANDLE thread_handle;
};

struct t_thread_runner* t_thread_runner_create(thread_func_call func,void* param)
{
    struct t_thread_runner* runner = MALLOC(sizeof(struct t_thread_runner));
    runner->func = func;
    runner->param = param;
    return runner;
}
void t_thread_runner_destroy(struct t_thread_runner* runner)
{
    t_thread_runner_join(runner);
    FREE(runner);
}
static void start_thread(void* param)
{
    struct t_thread_runner* runner = (struct t_thread_runner*) param;
    while(runner->running ==0)
    {
        t_thread_sleep_ms(10);
    }
    runner->func(runner);
}
int t_thread_runner_start(struct t_thread_runner* runner ,int stack_size)
{
    uintptr_t retval = _beginthread(start_thread,stack_size,runner);
    if(retvalue <=0)
    {
        return 0;
    }
    runner->thread_handle = (HANDLE) retvalue;
    runner->thread_id = GetThreadId(runner->thread_handle);
    runner->running = 1;
    return 1;
}
void t_thread_runner_stop(struct t_thread_runner* runner)
{
    runner->running = 0;
}
thread_id_t t_thread_get_id(struct t_thread_runner* runner)
{
    return runner->thread_id;
}
void t_thread_runner_join(struct t_thread_runner* runner)
{
    if(!runner->thread_handle)
    {
        return;
    }
    WaitForSingleObject(runner->thread_handle,INFINITE);
    runner->thread_id = 0;
}
thread_id_t t_thread_get_self()
{
    return GetCurrentThreadId();
}
void t_thread_sleep_ms(int ms)
{
    Sleep(ms);
}
t_atomic atomic_int(t_atomic* counter)
{
    return InterlockedIncrement(counter);
}
t_atomic atomic_dec(t_atomic* counter)
{
    return InterlockedDecrement(counter);
}
t_atomic atomic_cas(t_atomic* counter,t_atomic target,t_atomic value)
{
    return InterlockCompareExchange(counter,value,target);
}
t_atomic atomic_set(t_atomic* counter,t_atomic value)
{
    return InterlockedExchange(counter,value);
}
int atomic_zero(t_atomic* counter)
{
    return (*counter = 0);
}

struct t_lock
{
    CRITICAL_SECTION lock;
}

struct t_lock* t_lock_create()
{
    struct t_lock* lock = MALLOC(sizeof(struct t_lock));
    InitializeCriticalSection(&lock->lock);
    return lock;
}
void t_lock_destroy(struct t_lock* lock)
{
    DeleteCriticalSection(&lock->lock);
    FREE(lock);
}

void t_lock_lock(struct t_lock* lock)
{
    EnterCriticalSection(&lock->lock);
}
int t_lock_trylock(struct t_lock* lock)
{
    if(TryEnterCriticalSection(&lock->lock) == false)
    {
        return 0;
    }
    return 1;
}
void t_lock_unlock(struct t_lock* lock)
{
    LeaveCriticalSection(&lock->lock);
}

struct t_rwlock
{
    SRWLock rwlock;
}

struct t_rwlock* t_rwlock_create()
{
    struct t_rwlock* rwlock = MALLOC(sizeof(struct t_rwlock));
    InitializeSRWLock(&rwlock->rwlock);
    return rwlock;
}
void t_rwlock_destroy(struct t_rwlock* rwlock){}
void t_rwlock_rdlock(struct t_rwlock* rwlock)
{
    AcquireSRWLockShared(&rwlock->rwlock);
}
void t_rwlock_rdunlock(struct t_rwlock* rwlock)
{
    ReleaseSRWLockShared(&rwlock->rwlock);
}
void t_rwlock_wrlock(struct t_rwlock* rwlock)
{
    AcquireSRWLockExclusive(&rwlock->rwlock);
}
void t_rwlock_wrunlock(struct t_rwlock* rwlock)
{
    ReleaseSRWLockExclusive(&rwlock->rwlock);
}

struct t_cond
{
    HANDLE cond;
}

struct t_cond* t_cond_create()
{
    struct t_cond* cond = MALLOC(sizeof(struct t_cond));
    cond->cond = CreateEvent(0,TRUE,FALSE,0);
    if(cond->cond == INVALID_HANDLE_VALUE)
    {
        FREE(cond);
        return NULL;
    }
    return cond;
}
void t_cond_destroy(struct t_cond* cond)
{
    CloseHandle(cond->cond);
    FREE(cond);
}
void t_cond_wait(struct t_cond* cond,struct t_lock* lock)
{
    t_lock_unlock(lock);
    WaitForSingleObject(cond->cond,INFINITE);
    t_lock_lock(lock);
}
void t_cond_signal(struct t_cond* cond)
{
    SetEvent(cond->cond);
}